<template>
  <div ref="canvas"></div>
</template>

<script lang="ts" setup>
import * as THREE from "three";
import Stats from "three/examples/jsm/libs/stats.module";
import { GUI } from "three/examples/jsm/libs/lil-gui.module.min.js";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { ref, onMounted } from "vue";
import {PDBLoader} from "three/examples/jsm/loaders/PDBLoader";

const canvas = ref<any>();

const scene = new THREE.Scene();

const renderer = new THREE.WebGLRenderer({ antialias : true });
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.setClearColor(0x000000);
renderer.setPixelRatio(window.devicePixelRatio);
renderer.shadowMap.enabled = true;
renderer.shadowMap.type = THREE.PCFSoftShadowMap;

const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight);
camera.position.set(10, 10, 10);
camera.lookAt(0, 0, 0);

const orbitControl = new OrbitControls(camera, renderer.domElement);
orbitControl.update();

const stat = Stats();

const keyLight = new THREE.SpotLight(0xffffff);
keyLight.position.set(0, 80, 80);
keyLight.intensity = 2;
keyLight.lookAt(new THREE.Vector3(0, 15, 0));
keyLight.castShadow = true;
keyLight.shadow.mapSize.height = 4096;
keyLight.shadow.mapSize.width = 4096;
scene.add(keyLight);

const backlight1 = new THREE.SpotLight(0xaaaaaa);
backlight1.position.set(150, 40, -20);
backlight1.intensity = 0.5;
backlight1.lookAt(new THREE.Vector3(0, 15, 0));
scene.add(backlight1);

const backlight2 = new THREE.SpotLight(0xaaaaaa);
backlight2.position.set(-150, 40, -20);
backlight2.intensity = 0.5;
backlight2.lookAt(new THREE.Vector3(0, 15, 0));
scene.add(backlight2);

const loader = new PDBLoader();
loader.load(
    new URL("@/assets/models/molecules/diamond.pdb", import.meta.url).href,
    (geom) => {
      const group = new THREE.Group();

      // create the atoms
      const geometryAtoms = geom.geometryAtoms;

      for (let i = 0; i < geometryAtoms.attributes.position.count; i++) {
        const startPosition = new THREE.Vector3();
        startPosition.x = geometryAtoms.attributes.position.getX(i);
        startPosition.y = geometryAtoms.attributes.position.getY(i);
        startPosition.z = geometryAtoms.attributes.position.getZ(i);

        const color = new THREE.Color();
        color.r = geometryAtoms.attributes.color.getX(i);
        color.g = geometryAtoms.attributes.color.getY(i);
        color.b = geometryAtoms.attributes.color.getZ(i);

        const material = new THREE.MeshPhongMaterial({
          color: color
        });

        const sphere = new THREE.SphereGeometry(0.2);
        const mesh = new THREE.Mesh(sphere, material);
        mesh.position.copy(startPosition);
        group.add(mesh);
      }

      // create the bindings
      const geometryBonds = geom.geometryBonds;

      for (let j = 0; j < geometryBonds.attributes.position.count; j += 2) {
        const startPosition = new THREE.Vector3();
        startPosition.x = geometryBonds.attributes.position.getX(j);
        startPosition.y = geometryBonds.attributes.position.getY(j);
        startPosition.z = geometryBonds.attributes.position.getZ(j);

        const endPosition = new THREE.Vector3();
        endPosition.x = geometryBonds.attributes.position.getX(j + 1);
        endPosition.y = geometryBonds.attributes.position.getY(j + 1);
        endPosition.z = geometryBonds.attributes.position.getZ(j + 1);

        // use the start and end to create a curve, and use the curve to draw
        // a tube, which connects the atoms
        const path = new THREE.CatmullRomCurve3([startPosition, endPosition]);
        const tube = new THREE.TubeGeometry(path, 1, 0.04);
        const material = new THREE.MeshPhongMaterial({
          color: 0xcccccc
        });
        const mesh = new THREE.Mesh(tube, material);
        group.add(mesh);
      }

      scene.add(group);
    }
);

const render = () => {
  stat.update();

  requestAnimationFrame(render);
  renderer.render(scene, camera);
};

onMounted(() => {
  canvas.value.appendChild(stat.domElement);
  canvas.value.appendChild(renderer.domElement);

  render();
});

</script>
